#include "tm1637.h"
#include "stm32f1xx_hal.h"
#include <stdbool.h>

unsigned char Digital_tube_code_table[] =
{
    0x3F,  //"0"
    0x06,  //"1"
    0x5B,  //"2"
    0x4F,  //"3"
    0x66,  //"4"
    0x6D,  //"5"
    0x7D,  //"6"
    0x07,  //"7"
    0x7F,  //"8"
    0x6F,  //"9"
    0x77,  //"A"
    0x7C,  //"B"
    0x39,  //"C"
    0x5E,  //"D"
    0x79,  //"E"
    0x71,  //"F"
    0x76,  //"H"
    0x38,  //"L"
    0x37,  //"n"
    0x3E,  //"u"
    0x73,  //"P"
    0x5C,  //"o"
    0x40,  //"-"
    0x00  //熄灭
 
};

// 最高位设置为1时显示 数码管上的":" 符号
unsigned char disp_num[] = {0x3F, 0x06 | 0x80, 0x5B, 0x4F, 0x66, 0x6D};			//存放6个数码管要显示的内容

/* IIC部分代码 */
static void iic_delay_us(uint32_t udelay)
{
    __IO uint32_t Delay = udelay * 72 / 8;//(SystemCoreClock / 8U / 1000000U)
    //stm32f1xx_hal_rcc.c -- static void RCC_Delay(uint32_t mdelay)
    do
    {
    __NOP();
    }
    while (Delay --);
}


void iic_w_sda(uint8_t value)
{
    HAL_GPIO_WritePin(SDA_GPIO_PORT, SDA_Pin, (GPIO_PinState)value);
	iic_delay_us(10);
}
void iic_w_scl(uint8_t value)
{
    HAL_GPIO_WritePin(SCL_GPIO_PORT, SCL_Pin, (GPIO_PinState)value);
	iic_delay_us(10);
}
uint8_t iic_r_sda(void)
{
	uint8_t value;
    value = HAL_GPIO_ReadPin(SDA_GPIO_PORT,SDA_Pin);
	iic_delay_us(10);
	return value;
}

void iic_init(void)
{
     GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(SCL_GPIO_PORT, SCL_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(SDA_GPIO_PORT, SDA_Pin, GPIO_PIN_SET);
    /*Configure GPIO pins : PBPin PBPin */
    GPIO_InitStruct.Pin = SCL_Pin ;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(SCL_GPIO_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = SDA_Pin ;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(SDA_GPIO_PORT, &GPIO_InitStruct);
}

/**
  * @brief           iic_start
  * @param[in]       void
  * @retval          void
  * @author	         Jaychou
  * @date		     2024-06-29
  * @Description    确保释放SDA和SCL，先拉低SDA，再拉低SCL(即在SCL高电平期间，SDA来下降沿)
  */
void iic_start(void)
{
	iic_w_sda(1);
	//兼容重复起始条件(即SCL此时为低电平，SDA电平无法确定)//如果先将SCL拉高，SDA如果是由低到1高会产生终止条件
    iic_w_scl(1);	  
	iic_w_sda(0);
    iic_w_scl(0);
}
void iic_stop(void)
{
    iic_w_sda(0);																	//SDA不一定是低电平，所以开始时先拉低
	iic_w_scl(1);	  
	iic_w_sda(1);
}
/**
  * @brief           iic_start
  * @param[in]       void
  * @retval          void
  * @author	         Jaychou
  * @date		     2024-06-29
  * @Description    scl低电平期间，主机将数据放于sda上 
  */
void iic_send_byte(uint8_t byte)
{
    /* 低位先行 */
	uint8_t i;
	for (i = 0; i < 8; i ++)
	{
		iic_w_sda(byte & (0x01 << i));							//先放最低位，左移i位 
		iic_w_scl(1);											//每放一位施行释放SCL拉低SCL
		iic_w_scl(0);											//SCL以低位结束，方便拼接
	}	
    
}
uint8_t iic_receive_byte(void)									//接收一个字节
{
	uint8_t i, Byte = 0x00;
	iic_w_sda(1);												//主机先释放SDA。释放SDA相当于切换为输入模式
	for (i = 0; i < 8; i ++)
	{
		iic_w_scl(1);											//主机释放SCL(高电平期间) 允许读取数据
		if(iic_r_sda() == 1){Byte |= (0x80 >> i);}	//右移i位
		iic_w_scl(0);											//读取一位完毕，则拉低SCL
	}
	return Byte;
}
void iic_send_ack(uint8_t AckBit)								//发送应答
{
    iic_w_sda(AckBit);							            
	iic_w_scl(1);																//scl高电平从机读取
	iic_w_scl(0);													 			//SCL以低位结束，方便拼接
}

uint8_t iic_receive_ack(void)										 //接收应答
{
	uint8_t AckBit;
	iic_w_sda(1);        													//主机释放SDA，从机把应答位放到SDA上
	iic_w_scl(1);        													//SCL高电平，主机读取应答位
	AckBit = iic_r_sda();													//主机读取应答位 ，读到0代表从机给予应答
	iic_w_scl(0);        													//SCL低电平进入下一个时序单元
	return AckBit;
}

void tm1637_init(void)
{
    iic_init();
}

void tm1637_display_inc(void)
{
    uint8_t i;
    iic_start();
    iic_send_byte(ADDRESS_PLUS);
    iic_receive_ack();
    iic_stop();
    iic_start();
    iic_send_byte(0xC0);
    iic_receive_ack();
    
    for(i = 0; i < 6; i++)
    {
       iic_send_byte(Digital_tube_code_table[i]); 
       iic_receive_ack();   
    }
    iic_stop();
}

//写显示寄存器  地址不自增
// add 数码管的地址 0--5
// value 要显示的内容
void digi_tube_disp( uint8_t address, uint8_t value )
{
    iic_start();
    iic_send_byte(ADDRESS_FIXED);
    iic_receive_ack();
    iic_stop();
    
    iic_start();
    iic_send_byte(0xC0 | address);
    iic_receive_ack();
    
    iic_send_byte(Digital_tube_code_table[value]);
    iic_receive_ack();
    iic_stop();

}

void digi_tube_set_bri(unsigned char level)
{
    iic_start();
    iic_send_byte(DISPLAY_ON | level);
    iic_receive_ack();
    iic_stop();
}

void digi_tube_off(void)
{
    iic_start();
    iic_send_byte(DISPLAY_OFF);
    iic_receive_ack();
    iic_stop();
}
